import {AxiosRequestConfig, AxiosPromise, AxiosResponse} from "./types/index";
import { parseHeaders } from "./helpers/headers";

import { createError } from "./helpers/error";

export default function xhr(config: AxiosRequestConfig): AxiosPromise{

    return new Promise((resolve, reject) => {


        const {data = null, url, method="GET", headers, responseType, timeout} = config

        const request = new XMLHttpRequest()

        if(responseType){
            request.responseType = responseType
        }

        if(timeout){
            request.timeout = timeout
        }

        request.open(method.toUpperCase(), url!, true)

        request.onreadystatechange = function  handleLoad(){
            if(request.readyState !== 4){
                return
            }

            if(request.status === 0 ){
                return
            }

            const responseHeaders = parseHeaders(request.getAllResponseHeaders())
            const responseData =  responseType !== 'text' ? request.response : request.responseText

            const response: AxiosResponse = {
                data: responseData,
                status: request.status,
                statusText: request.statusText,
                headers: responseHeaders,
                config,
                request
            }
           handlerResponse(response)
        }

        request.ontimeout = function handlerTimeout(){
            reject(createError(`Timeout of ${timeout}`, config, 'ECONNABORTED', request))
        }

        request.onerror = function handlerError(){
            reject(createError('network error', config, null, request))
        }

        Object.keys(headers).forEach(name=>{
            if(data === null && name.toLowerCase() === 'content-type'){
                delete headers[name]
            }else {
                request.setRequestHeader(name, headers[name])
            }
        })

        request.send(data)

        function handlerResponse(res: AxiosResponse): void{
            if(res.status >= 200 && res.status < 300){
                resolve(res)
            }else{
                reject(createError(`Request failed status code $res.status}`, config, null, request))
            }
        }

    })
}